/**
 * @author Hamid Ebadi
 *
 */
public class Calculator3 {
	// operators 
	private enum CalcOperator {
		PLUS, MINUS , MULTIPLY , DIVISION , EQUAL, BRACKET, UNDEFINED;
	}
	// Calculate State 
	private CalcOperator CSoperator ;
	private Integer CSoperand  ;
	private Boolean CSValidBuffer ;   
	private String CSbuffer  ;
	private Boolean InBracket ;
	private Calculator3 BracketCalc ;
	private Boolean ErrorState= false ;
	// Methods
	// Constructor 
	Calculator3 (){
		pressReset();
	}
	/*
	 * I : Initial State
	 * N : reading Number 
	 * O : Reading operation
	 * E: Error state
	 */
	public String CalcState(){
		if (ErrorState == true ) return "E";
		if (CheckInBracket()){
			return BracketCalc.CalcState();
		}else {
			if (CSbuffer=="" && CSoperand == 0 && CSoperator == CalcOperator.UNDEFINED  && CSValidBuffer ==false) return "I";
			else if (CSValidBuffer == true && CSbuffer.length() >0 ) return "N";
			else if (CSValidBuffer == false && CSoperator != CalcOperator.UNDEFINED) return "O" ;
			else return "E";
		}

	}
	public Boolean CheckError(){
		return ErrorState || (BracketCalc != null && BracketCalc.CheckError()) ;
	}
	public Boolean CheckInBracket(){
		return InBracket;
	}
	public void pressReset(){
		ErrorState = false ;
		CSbuffer = "" ;
		CSoperand = 0 ;
		CSoperator= CalcOperator.UNDEFINED ;
		CSValidBuffer = false;
		InBracket= false;
		BracketCalc= null;
	}
	
	public void pressOpenBracket(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			BracketCalc.pressOpenBracket();
		} else {
			
			if (CalcState().equals("N")){
				ErrorState = true ;
				return ;
			}
			InBracket = true ;
			BracketCalc = new Calculator3();
		}
	}
	public void pressCloseBracket(){
		if (CheckError()) return ;
		if (CheckInBracket()){
			if(BracketCalc.CheckInBracket()) {
				BracketCalc.pressCloseBracket();
			} else {
				if (BracketCalc.CSValidBuffer == false    ) {
					ErrorState = true ;
					return ;
				} else {
					InBracket = false ;
					BracketCalc.pressEqual();
					Integer tmp = BracketCalc.getOperand();
					CSbuffer = tmp.toString() ;
					CSValidBuffer= true ;
					pressEqual();
					CSoperator = CalcOperator.BRACKET;
				}
			}
		}else {
			ErrorState = true;
			System.out.println("Unbalanced brackets (Close bracket)");
		}
	}
	public void pressDigit(char digit){
		if (CheckError()) return ;
		if (CSoperator== CalcOperator.BRACKET) {
			ErrorState = true ;
			return ;
		}
		if(CheckInBracket()) {
			BracketCalc.pressDigit(digit);
		} else {
			if (!Character.isDigit(digit)){
				System.out.println("Invalid digit" );
			}else {		  
				if (CSValidBuffer){
					CSbuffer  = CSbuffer + digit ;
				}else {
					CSbuffer = String.valueOf(digit);
					CSValidBuffer = true ;
				}
			}
		}

	}
	public void pressPlus(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			BracketCalc.pressPlus();
		} else {
			pressOp(CalcOperator.PLUS);
		}
	}
	public void pressMinus(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			BracketCalc.pressMinus();
		} else {
			pressOp(CalcOperator.MINUS);
		}
	}
	public void pressMult(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			BracketCalc.pressMult();
		} else {
			pressOp(CalcOperator.MULTIPLY);
		}
	}
	public void pressDiv(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			BracketCalc.pressDiv();
		} else {
			pressOp(CalcOperator.DIVISION);
		}
	}
	public void pressEqual(){
		if (CheckError()) return ;
		if(CheckInBracket()) {
			//BracketCalc.pressEqual();
			ErrorState = true ;
			return ;
		} else {
			pressOp(CalcOperator.EQUAL);
		}
	}
	public String getBuffer(){
		return CSbuffer;	
	}
	public int getOperand() {
		return CSoperand;
	}
	private void setOperand(Integer value){
		CSoperand = value ;		
	}
	private Integer BufferToInteger(){
		if (CSbuffer.length()<4){
			return Integer.valueOf(CSbuffer);
		}else {
			System.out.println("too long digit");
			return 0; 
		}
	}
	private void pressOp(CalcOperator op) {
		if (CalcState().equals("I")){
			ErrorState=true ;
			return ;
		}
		if (CSValidBuffer ) // we read the number but we have not read the operator yet 
		{
			if (CSoperator == CalcOperator.PLUS) setOperand(  getOperand() + BufferToInteger());
			if (CSoperator == CalcOperator.MINUS) setOperand( getOperand() - BufferToInteger());
			if (CSoperator == CalcOperator.DIVISION) {
				Integer divisor = BufferToInteger() ;
				if (divisor == 0 ){
					System.out.println("Division by zero" ); 
				} else {
					setOperand( getOperand() / divisor );
				}
			}
			if (CSoperator == CalcOperator.MULTIPLY) setOperand( getOperand() *BufferToInteger());
			if (CSoperator == CalcOperator.EQUAL) setOperand( BufferToInteger());
			if (CSoperator == CalcOperator.UNDEFINED) setOperand( BufferToInteger());
		}
		CSoperator  = op ;
		CSValidBuffer = false ;
	}
	public static void main(String[] args) {
		Calculator3 calc= new Calculator3();
		if (args.length < 1) System.out.println("Missing command-line arguments. ( e.g. 1+3 -4= )\n " );
		for (int i = 0 ; i!= args.length ; i++) {
			for (int j = 0 ; j!= args[i].length() ; j++) {
				char ch = args[i].charAt(j) ;
				if (Character.isDigit(ch)){
					calc.pressDigit(ch);
				}
				switch(ch){
				case '+' :
					calc.pressPlus();
					break;
				case '-' :
					calc.pressMinus();
					break;
				case '/':
					calc.pressDiv();
					break;
				case '*':
					calc.pressMult();
					break;
				case '=':
					calc.pressEqual();
					break;
				case '(':
					calc.pressOpenBracket();
					break;
				case ')':
					calc.pressCloseBracket();
					break;	
				default :
					
				}
				Boolean b = calc.CheckInBracket();
				
				System.out.println("Result of proccessing \"" + ch + "\" : Operand(Memory):" + calc.getOperand()+ ", Digit buffer:" + calc.getBuffer() + ",\tCalc State:" + calc.CalcState());
				System.out.println("InBracket: " + b);
			}
		}

	}

}